#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/*
 * Copyright © 2014, Finium Sdn Bhd, All Rights Reserved
 * 
 * ValidationUtil.java
 * Modification History
 * *************************************************************
 * Date				Author						Comment
 * Feb 25, 2012		Venkaiah Chowdary Koneru	Created
 * *************************************************************
 */
package ${package}.commons.support.validation;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.groups.Default;

import ${package}.support.CommonsUtil;
import ${package}.support.threadlocals.ThreadLocalErrorContext;
import ${package}.support.validation.SecondGroup;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.MessageSource;
import org.springframework.util.Assert;

/**
 * Validation Util class.
 * 
 * @author Venkaiah Chowdary Koneru
 */
public final class ValidationUtil
{
    private static final Log LOG = LogFactory.getLog(ValidationUtil.class);
    private static final String DUPLICATE_VIOLATION_LOG_MSG = "A violation with the same property %s exists. so skipping this duplicate violation...";

    // Make sure the order is not changed for the proper validation
    private static Class<?>[] groups = new Class<?>[] { Default.class,
            SecondGroup.class };

    /**
     * Constructor. Private to prevent unnecessary instantiation.
     */
    private ValidationUtil()
    {

    }

    /**
     * Validates a DTO Object against all validation groups. <br/>
     * This helper method is intended for grabbing all the messages across all
     * the groups instead of one group single time.
     * 
     * @param dto
     *            the object that need to be validated
     * @param validator
     *            the JSR-303 Validator instance
     * @return A Map of error codes as keys and same as values
     */
    public static Map<String, String> validateDTO(final Object dto,
            final Validator validator)
    {
        Assert.notNull(validator);

        Map<String, String> errors = new LinkedHashMap<String, String>();

        for (Class<?> group : groups)
        {
            Set<ConstraintViolation<Object>> violations = validator.validate(
                    dto, group);

            processConstraintVoilations(violations, errors);
        }

        return errors;
    }

    /**
     * helper method to process constraint violations and put every violation
     * into a Map
     * 
     * @param violations
     *            The JSR-303 ConstraintViolation results
     * @param errors
     *            a non-null hash map to store the processed violations
     */
    public static void processConstraintVoilations(
            final Set<ConstraintViolation<Object>> violations,
            final Map<String, String> errors)
    {
        Assert.notNull(errors);

        for (ConstraintViolation<Object> violation : violations)
        {
            if (!errors.containsKey(violation.getPropertyPath().toString()))
            {
                errors.put(violation.getPropertyPath().toString(),
                        violation.getMessage());
            }
            else
            {
                LOG.trace(String.format(DUPLICATE_VIOLATION_LOG_MSG, violation
                        .getPropertyPath().toString()));
            }
        }
    }

    /**
     * used to parse any attached errors to thread local
     * 
     * @param errors
     *            a non-null hash map to store the processed violations
     */
    public static void processThreadLocalViolations(
            final Map<String, String> errors)
    {
        Assert.notNull(errors);

        if (!CommonsUtil.isEmpty(ThreadLocalErrorContext.get()))
        {
            List<String> threadLocalErrors = ThreadLocalErrorContext.get();

            for (String errorKey : threadLocalErrors)
            {
                errors.put(errorKey, null);
            }
        }

        ThreadLocalErrorContext.unset();
    }

    /**
     * 
     * @param messageSource
     * @param errors
     *            a hashmap which contains the processed constraint violations.
     * @return A Map of error codes as keys and parsed messages
     */
    public static Map<String, String> parseErrorMessages(
            final MessageSource messageSource, final Map<String, String> errors)
    {
        Assert.notNull(messageSource);

        if (!CommonsUtil.isEmpty(errors))
        {
            Map<String, String> parsedMap = new HashMap<String, String>();
            for (Entry<String, String> entry : errors.entrySet())
            {
                parsedMap.put(entry.getKey(),
                        messageSource.getMessage(entry.getValue(), null, null));
            }

            return parsedMap;
        }

        return null;
    }
}